import { Code } from '~/components/text/code'
import { HelpLink } from '~/components/text/link'
import Note from '~/components/text/note'
import Endpoint from '~/components/api/endpoint'
import Request from '~/components/api/request'

export const meta = {
  editUrl: 'pages/docs/api/v2/api-docs-mdx/endpoints/log-drains.mdx',
  lastEdited: '2019-11-13T11:50:09.000Z'
}

## Log Drains

Log Drains allow you to collect logs from your deployments. To enable Log Drains, you must provide a destination URL to send the logs to.

We send logs to destination URLs over `HTTPS`, `HTTP`, `TLS`, or `TCP` every time logs are generated.

### List all Log Drains

<Endpoint method="GET" url="/v1/integrations/log-drains" />

Retrieves a list of all Log Drains that are defined for the authorized account.

### Create a Log Drain

<Endpoint method="POST" url="/v1/integrations/log-drains" />

Creates a new Log Drain subscription.

#### Request Parameters

| Key           | <HelpLink href="#api-basics/types" hasIcon>Type</HelpLink> | Required | Description                                                                                                                                                           |
| ------------- | ---------------------------------------------------------- | -------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| **name**      | <HelpLink href="#api-basics/types">String</HelpLink>       | Yes      | The name of the drain.                                                                                                                                                |
| **type**      | <HelpLink href="#api-basics/types">String</HelpLink>       | Yes      | The type of log format, one of `json`, `ndjson` or `syslog`.                                                                                                          |
| **url**       | <HelpLink href="#api-basics/types">String</HelpLink>       | Yes      | The URL where you will receive logs. The protocol must be `https://` or `http://` for the type `json` and `ndjson`, `syslog+tls:` or `syslog:` for the type `syslog`. |
| **projectId** | <HelpLink href="#api-basics/types">ID</HelpLink>           | No       | The ID of a project to subscribe.                                                                                                                                     |

See the [Format and Transport](#endpoints/log-drains/format-and-transport) section for more details on the types.

#### Response Parameters

| Key                 | <HelpLink href="#api-basics/types" hasIcon>Type</HelpLink> | Description                                                               |
| ------------------- | ---------------------------------------------------------- | ------------------------------------------------------------------------- |
| **id**              | <HelpLink href="#api-basics/types">ID</HelpLink>           | The unique identifier of the drain. Always prefixed with `ld_`.           |
| **name**            | <HelpLink href="#api-basics/types">String</HelpLink>       | The name of the Log Drain.                                                |
| **type**            | <HelpLink href="#api-basics/types">String</HelpLink>       | The type of log format.                                                   |
| **url**             | <HelpLink href="#api-basics/types">String</HelpLink>       | The URL to call when logs for the Log Drain is triggered.                 |
| **ownerId**         | <HelpLink href="#api-basics/types">ID</HelpLink>           | The identifier of the team or user whose logs will trigger the Log Drain. |
| **projectId**       | <HelpLink href="#api-basics/types">ID</HelpLink>           | The identifier of the project to be subscribed.                           |
| **clientId**        | <HelpLink href="#api-basics/types">ID</HelpLink>           | The identifier of the client which created the Log Drain.                 |
| **configurationId** | <HelpLink href="#api-basics/types">ID</HelpLink>           | The identifier of the configuration which created the Log Drain.          |
| **createdAt**       | <HelpLink href="#api-basics/types">Date</HelpLink>         | A timestamp that tells you when the Log Drain was created.                |

##### Example Request

<Request
  method="POST"
  url="https://api.zeit.co/v1/integrations/log-drains"
  headers={{
    'Content-Type': 'application/json'
  }}
  auth
  body={{
    name: 'My first Log Drain',
    type: 'json',
    url: 'https://user:pass@my-log-drain-handler.com/zeit',
    projectId: 'abcdefgdufoJxB6b9b1fEqr1jUtFkyavUURbnDCFCnZxgs'
  }}
/>

##### Example Response

<Code lang="json">{`{
  "id": "ld_XCG7t7AIHuO2SBA8667zNUiM",
  "url": "https://user:pass@my-log-drain-handler.com/zeit",
  "name": "My first Log Drain",
  "type": "json",
  "ownerId": "kr1PsOIzqEL5Xg6M4VZcZosf",
  "projectId": "abcdefgdufoJxB6b9b1fEqr1jUtFkyavUURbnDCFCnZxgs"
  "clientId": "oac_xbk2e7gE1XYr37jTgAV4ewX6",
  "configurationId": "icfg_8ygXBI4T7VCjxZLYopICFWzX",
  "createdAt": 1558531915505
}`}</Code>

### Delete a Log Drain

<Endpoint method="DELETE" url="/v1/integrations/log-drains/:id" />

Deletes the Log Drain with the provided `id`.

### Format and Transport

We support 3 types of Log Drains:

- JSON
- NDJSON
- Syslog

### JSON drains

When you choose the `json` type, the URL receives a HTTPS or HTTP POST request with a JSON array on the `POST` body.
The logs are buffered and submitted as batches with the following formats:

<Code lang="json">{`[
  {
    "id": <identifier>,
    "message": <text>,
    "timestamp": <timestamp>,
    "type": <"stdout" or "stderr">,
    "source": <"build", "static" or "lambda">,
    "projectId": <identifier of project>,
    "deploymentId": <identifier of deployement>,
    "buildId": <identifier of build>,
    "host": <hostname>,
    "entrypoint": <entrypoint>
  },
  {
    "id": <identifier>,
    "message": <text>,
    "timestamp": <timestamp>,
    "requestId": <identifier of request only on runtime logs>,
    "statusCode": <HTTP status code of request only on runtime logs>,
    "source": <"build", "static" or "lambda">,
    "projectId": <identifier of project>,
    "deploymentId": <identifier of deployement>,
    "buildId": <identifier of build only on build logs>,
    "host": <hostname>,
    "path": <path>,
    "proxy": {
      "timestamp": <timestamp of proxy request>,
      "method": <method of request>,
      "scheme": <protocol of request>,
      "host": <hostname>,
      "path": <path of proxy request>,
      "userAgent": <user agent>,
      "referer": <referer>,
      "statusCode": <HTTP status code of proxy request>,
      "clientIp": <client IP>,
      "region": <region request is processed>,
      "cacheId": <original request id when request is served from cache>,
    }
  }
]`}</Code>

The requests are posted with a `x-zeit-signature` header which contains a hash signature you can use to validate the request body.
See the [Securing your Log Drains](#endpoints/log-drains/securing-your-log-drains) section to learn how to verify requests.

### NDJSON Drains

When you choose the `ndjson` type, the URL receives a HTTPS or HTTP POST request with JSON objects delimited by newline (`\\n`) on the `POST` body.
See [ndjson.org](http://ndjson.org) for more information on the structure.

Each request receives HTTP headers including `x-zeit-signature`.

The following is an example `POST` body:

<Code lang="json">{`{"id":"1573817187330377061717300000","message":"done","timestamp":1573817187330,"type":"stdout","source":"build","projectId":"abcdefgdufoJxB6b9b1fEqr1jUtFkyavUURbnDCFCnZxgs","deploymentId":"dpl_233NRGRjVZX1caZrXWtz5g1TAksD","buildId":"bld_cotnkcr76","host":"example-4lp0kffgq.now.sh","entrypoint":"api/index.js"}
{"id":"1573817250283254651097202070","message":"START RequestId: 643af4e3-975a-4cc7-9e7a-1eda11539d90 Version: $LATEST\\n2019-11-15T11:27:30.721Z\\t643af4e3-975a-4cc7-9e7a-1eda11539d90\\tINFO\\thello\\nEND RequestId: 643af4e3-975a-4cc7-9e7a-1eda11539d90\\nREPORT RequestId: 643af4e3-975a-4cc7-9e7a-1eda11539d90\\tDuration: 16.76 ms\\tBilled Duration: 100 ms\\tMemory Size: 1024 MB\\tMax Memory Used: 78 MB\\tInit Duration: 186.49 ms\\t\\n","timestamp":1573817250283,"source":"lambda","requestId":"894xj-1573817250172-7847d20a4939","statusCode":200,"proxy":{"timestamp":1573817250172,"path":"/api","userAgent":["Mozilla/5.0 (Macintosh; Intel Mac OS X 10_14_6) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/78.0.3904.97 Safari/537.36"],"referer":"http://example.now.sh","method":"GET","scheme":"https","host":"example-4lp0kffgq.now.sh","statusCode":200,"clientIp":"120.75.16.101","region":"sfo1"},"projectId":"abcdefgdufoJxB6b9b1fEqr1jUtFkyavUURbnDCFCnZxgs","deploymentId":"dpl_233NRGRjVZX1caZrXWtz5g1TAksD","host":"example-4lp0kffgq.now.sh","path":"api/index.js"}`}</Code>

### Syslog Drain

When you choose the `syslog` type, the URL is connected with TLS or TCP.
Log Drain messages are formatted according to [RFC5424](https://tools.ietf.org/html/rfc5424) framed using octet counting defined in [RFC6587](https://tools.ietf.org/html/rfc6587#section-3.4.1).

Syslog messages resemble the following:

```
425 <142>1 2019-11-15T11:42:22.562Z example-4lp0kffgq.now.sh now proxy - [proxy@54735 requestId="q8k4w-1573818142562-9adfb40ce9d4" statusCode="200" method="GET" path="/api" userAgent="Mozilla/5.0 (Macintosh; Intel Mac OS X 10_14_6) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/78.0.3904.97 Safari/537.36" referer="http://example.now.sh" clientIp="120.75.16.101" region="sfo1" signature="b847f4dd531d0b41094fb4b38fd62bde0b0e29a5"]587 <150>1 2019-11-15T11:42:22.833Z example-4lp0kffgq.now.sh now lambda - [lambda@54735 requestId="q8k4w-1573818142562-9adfb40ce9d4" statusCode="200" path="api/index.js" signature="0900101157dac2a2e555524c2f8d61229b15307d"] BOMSTART RequestId: ec00309f-4514-4128-8b8a-9a0e74900283 Version: $LATEST
2019-11-15T11:42:23.176Z\\tec00309f-4514-4128-8b8a-9a0e74900283\\tINFO\\thello
END RequestId: ec00309f-4514-4128-8b8a-9a0e74900283
REPORT RequestId: ec00309f-4514-4128-8b8a-9a0e74900283\\tDuration: 20.08 ms\\tBilled Duration: 100 ms Memory Size: 1024 MB\\tMax Memory Used: 77 MB\\tInit Duration: 157.97 ms
```

Similar to JSON and NDJSON drains, a syslog message contains a hash signature for verifying messages on the `signature` key of structured data.
On syslog drains, the signature is computed using an OAuth2 secret and the `MSG` section of the syslog format.

### Securing your Log Drains

All drains support transport-level encryption using `HTTPS` or `TLS` protocols,
and we strongly recommend using them on production and use others only for development and testing.

When your server starts receiving payloads, it could be a third party sending log messages to your server if they know the URL. Therefore, it is recommended to use HTTP Basic Authentication, or verify messages are sent from ZEIT using an OAuth2 secret and hash signature.

For example, if you have a basic HTTP server subscribing to Log Drains, the payload can be validated like so:

<Code lang="javascript">{`const http = require('http');
const crypto = require('crypto');
http.createServer((req, res) => {
  var body = '';
  req.on('data', function (chunk) {
    body += chunk;
  });
  req.on('end', function() {
    if (!verifySignature(req, body)) {
      res.statusCode = 403;
      res.end("signature didn't match");
      return;
    }
    res.end("ok");
  });
}).listen(3000);
function verifySignature(req, body) {
  const signature = crypto.createHmac('sha1', process.env.OAUTH2_SECRET)
    .update(body)
    .digest('hex');
  return signature === req.headers['x-zeit-signature'];
}
`}</Code>

You can compute the signature using an HMAC hexdigest from the `secret` token of the OAuth2 app and request body, then compare it with the value of the `x-zeit-signature` header to validate the payload.
